package com.linQing.waterWork.service.mongodb.impl;

import com.linQing.waterWork.modle.dto.CurveRequest;
import com.linQing.waterWork.modle.dto.ReportRequest;
import com.linQing.waterWork.modle.page.PageResult;
import com.linQing.waterWork.modle.vo.AnalogVo;
import com.linQing.waterWork.modle.vo.DataVo;
import com.linQing.waterWork.service.mongodb.ReportService;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【DayQuartZ】的数据库操作Service实现
 * @createDate 2024-04-23 14:32:33
 */
@Service
public class ReportServiceImpl implements ReportService {

    @Resource
    MongoTemplate mongoTemplate;

    @Resource
    private MongoClient mongoClient;


    @Override
    public List<AnalogVo> getReport(ReportRequest request) {
        // 获取开始时间和结束时间
        Date startDate = request.getStartTime();
        Date endDate = request.getEndTime();
        // 创建 Calendar 对象并设置开始时间
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);

// 创建 Calendar 对象并设置结束时间
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

// 开始时间加上八小时
        startCal.add(Calendar.HOUR, 8);

// 结束时间加上八小时
        endCal.add(Calendar.HOUR, 8);

// 获取新的开始时间和结束时间
        Date newStartTime = startCal.getTime();
        Date newEndTime = endCal.getTime();

        // 获取请求的设备ID和页码、每页大小
        String equipmentID = request.getEquipmentID();
        int pageNum = request.getPageNum();
        int pageSize = request.getPageSize();
        Set<String> requiredKeys = new HashSet<>(request.getDataIds());
        // 使用Calendar来获取年份
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate); // 设置calendar的时间为startDate
        int year = calendar.get(Calendar.YEAR); // 获取年份
        String dbName = "WNMS_CSNew" + year;

        // 获取数据库引用
        MongoDatabase db = mongoClient.getDatabase(dbName);

        // 获取集合引用
        MongoCollection<Document> collection = db.getCollection(equipmentID);

        // 构建查询条件
        Bson filter = Filters.and(
                Filters.gte("UpdateTime", new Date(newStartTime.getTime())),
                Filters.lt("UpdateTime", new Date(newEndTime.getTime()))
        );

        // 根据分页信息计算跳过的数量
        int skipNum = (pageNum - 1) * pageSize;

        // 创建FindIterable
        FindIterable<Document> iterable = collection.find(filter).skip(skipNum).limit(pageSize).sort(new Document("UpdateTime", 1));

        // 转换FindIterable为List
        List<Document> documents = new ArrayList<>();
        iterable.into(documents);
        List<AnalogVo> analogVoList = new ArrayList<>();
        for (Document document : documents) {
            AnalogVo analogVo = new AnalogVo();
            // 假设UpdateTime在Document中是以Date对象存储的
            Date updateTime = document.getDate("UpdateTime");
            // 将 updateTime 转换为毫秒数
            long updateTimeInMillis = updateTime.getTime();
            // 减去八小时的毫秒数
            long newTimeInMillis = updateTimeInMillis - (8 * 60 * 60 * 1000);
            // 创建新的 Date 对象
            Date newTime = new Date(newTimeInMillis);
            analogVo.setUpdateTime(newTime);
            // 假设AnalogValues在Document中是以Map<String, Double>对象存储的
            Map<String, Double> analogValues = document.get("AnalogValues", Map.class);
            // 过滤Map以仅包含所需的键
            Map<String, Double> typedAnalogValues = analogValues.entrySet().stream()
                    .filter(entry -> requiredKeys.contains(entry.getKey()))
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            analogVo.setAnalogValues(typedAnalogValues);
            // 添加转换后的CollVo到列表中
            analogVoList.add(analogVo);
        }

        return analogVoList;
    }

    @Override
    public List<DataVo> getDigital(String equipmentID) {

        // 使用Calendar来获取年份
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date()); // 设置calendar的时间为startDate
        int year = calendar.get(Calendar.YEAR); // 获取年份
        String dbName = "WNMS_CSNew" + year;

        // 获取数据库引用
        MongoDatabase db = mongoClient.getDatabase(dbName);

        // 获取集合引用
        MongoCollection<Document> collection = db.getCollection(equipmentID);

        // 创建FindIterable
        FindIterable<Document> iterable = collection.find()
                .sort(new Document("UpdateTime", -1)) // 使用降序排序以获取最新的记录
                .limit(1);
        Document document = iterable.first();

        // 检查是否找到了文档
        if (document != null) {
            DataVo dataVo = new DataVo();
            // 假设UpdateTime在Document中是以Date对象存储的
            Date updateTime = document.getDate("UpdateTime");
            dataVo.setUpdateTime(updateTime);
            // 假设DigitalValues在Document中是以Map<String, Boolean>对象存储的
            Map<String, Double> analogValues = document.get("AnalogValues", Map.class);
            Map<String, Boolean> digitalValues = document.get("DigitalValues", Map.class);
            dataVo.setAnalogValues(analogValues);
            dataVo.setDigitalValues(digitalValues);
            return Collections.singletonList(dataVo); // 返回只包含一个DigitalVo的列表
        } else {
            // 处理没有找到任何记录的情况
            return Collections.emptyList(); // 返回一个空的列表
        }

    }

    @Override
    public PageResult getAggregatedData(ReportRequest request) {
        // 计算跳过的文档数
        long totalDocs = 0;
        int pageSize = request.getPageSize();
        int currentPage = request.getPageNum();
        Date startDate = request.getStartTime();
        Date endDate = request.getEndTime();
        // 创建 Calendar 对象并设置开始时间
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);

// 创建 Calendar 对象并设置结束时间
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

// 开始时间加上八小时
        startCal.add(Calendar.HOUR, 8);

// 结束时间加上八小时
        endCal.add(Calendar.HOUR, 8);

// 获取新的开始时间和结束时间
        Date newStartTime = startCal.getTime();
        Date newEndTime = endCal.getTime();
        // 使用Calendar来获取年份
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate); // 设置calendar的时间为startDate
        int year = calendar.get(Calendar.YEAR); // 获取年份
        String dbName = "WNMS_CSNew" + year;

        // 查询总文档数
        MongoDatabase db = mongoClient.getDatabase(dbName);
        // 构建Query对象
        Document query = new Document();
        query.append("UpdateTime", new Document()
                .append("$gte", new Date(newStartTime.getTime()))
                .append("$lt", new Date(newEndTime.getTime())));


        // 获取集合的引用
        MongoCollection<Document> collection = db.getCollection(request.getEquipmentID());

        // 使用MongoCollection的countDocuments方法
        totalDocs = collection.countDocuments(query);
        // 计算总页数
        int totalPage = (int) Math.ceil((double) totalDocs / pageSize);
        List<AnalogVo> list = this.getReport(request);
        // 构建分页结果
        PageResult pageResult = new PageResult();
        pageResult.setList(list);
        pageResult.setTotalPages(totalPage);
        pageResult.setCurrentPage(currentPage);
        pageResult.setTotalElements(totalDocs);
        pageResult.setPageSize(pageSize);

        return pageResult;
    }

    public void updateDataDaily() {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now().minusMinutes(1);
// 将当前时间减去十分钟，得到开始时间
        LocalDateTime startTime = now.minusMinutes(8);
// 将开始时间和结束时间转换为UTC时间的Date对象
        Date startTimeUtc = Date.from(startTime.atZone(ZoneId.from(ZoneOffset.UTC)).toInstant());
        Date endTimeUtc = Date.from(now.atZone(ZoneId.from(ZoneOffset.UTC)).toInstant());

// 构建聚合查询操作
        List<AggregationOperation> operations = new ArrayList<>();
        operations.add(Aggregation.match(
                Criteria.where("UpdateTime").gte(startTimeUtc).lt(endTimeUtc)  // 昨天的开始时间到今天的开始时间
        ));
        // 构建ProjectOperation来计算时间差并准备分组
        operations.add(Aggregation.project()
                .andExpression("toLong(divide(toLong(UpdateTime), [0]))", 600000).as("timestamp")
                .andInclude("UpdateTime", "AnalogValues"));

        // 构建GroupOperation按每十分钟分组
        operations.add(Aggregation.group("timestamp")
                .last("timestamp").as("timestamp")
                .last("$$ROOT").as("firstDoc"));
        // 构建ProjectOperation来格式化日期和排除_id
        operations.add(Aggregation.project()
                .andExclude("_id")
                .andExpression("toDate(multiply(timestamp, 600000))").as("UpdateTime")
                .andInclude("firstDoc.AnalogValues"));

        operations.add(Aggregation.sort(Direction.ASC, "UpdateTime"));
        // 构建聚合查询
        Aggregation aggregation = Aggregation.newAggregation(operations);

        // 执行聚合查询
        AggregationResults<Document> aggregateResults = mongoTemplate.aggregate(
                aggregation,
                "1711501377427", // 替换为实际的集合名称
                Document.class
        );

        // 对第二个集合执行聚合查询
        AggregationResults<Document> aggregateResults2 = mongoTemplate.aggregate(
                aggregation,
                "1711501542211",
                Document.class
        );

        // 用于存储去重和合并后的数据
// 映射用于存储每个集合中UpdateTime对应的AnalogValues
        Map<Date, Document> documentsMapFirst = new HashMap<>();
        Map<Date, Document> documentsMapSecond = new HashMap<>();

// 填充第一个集合的映射
        for (Document document : aggregateResults.getMappedResults()) {
            Document analogValuesDoc = (Document) document.get("AnalogValues");
            Date updateTime = document.getDate("UpdateTime");
            documentsMapFirst.put(updateTime, analogValuesDoc); // 直接存储Document
        }

// 填充第二个集合的映射
        for (Document document : aggregateResults2.getMappedResults()) {
            Document analogValuesDoc = (Document) document.get("AnalogValues");
            Date updateTime = document.getDate("UpdateTime");
            documentsMapSecond.put(updateTime, analogValuesDoc);
        }

// 合并两个映射中UpdateTime相同的AnalogValues
        Map<Date, Document> mergedDocuments = new HashMap<>();

// 遍历第一个集合中的UpdateTime对应的AnalogValues
        documentsMapFirst.forEach((key, value) -> {
            // 为每个UpdateTime创建一个新的Document来存储合并后的AnalogValues
            Document mergedAnalogValues = new Document();

            // 将第一个集合的AnalogValues添加到合并后的Document中
            value.keySet().forEach(innerKey -> {
                mergedAnalogValues.append(innerKey, value.get(innerKey));
            });

            // 检查第二个集合中是否存在相同的UpdateTime
            if (documentsMapSecond.containsKey(key)) {
                // 如果存在，将第二个集合的AnalogValues也添加到合并后的Document中
                documentsMapSecond.get(key).keySet().forEach(innerKey -> {
                    // 如果键已经存在，则可能需要进行特定的合并逻辑（例如求和）
                    if (mergedAnalogValues.containsKey(innerKey)) {
                        //如果存在相同键,只保留1#2#的值
                        mergedAnalogValues.put(innerKey, mergedAnalogValues.get(innerKey));
                    } else {
                        mergedAnalogValues.append(innerKey, documentsMapSecond.get(key).get(innerKey));
                    }
                });
                // 将合并后的Document添加到mergedDocuments映射中
                mergedDocuments.put(key, mergedAnalogValues);
            }


        });
        // 检查新集合是否存在，如果不存在则创建
//            mongoTemplate.createCollection("linqing");
// 将合并后的数据转换为Document对象，并批量插入到新集合中
        if (!mergedDocuments.isEmpty()) {
            List<Document> allDocuments = new ArrayList<>();
            mergedDocuments.forEach((key, value) -> {
                Document doc = new Document();
                doc.append("UpdateTime", key);
                doc.append("AnalogValues", value);
                allDocuments.add(doc);
            });
            for (Document document : allDocuments) {
                mongoTemplate.insert(document, "linqing");
            }
        }
    }

    @Override
    public List<AnalogVo> getCurve(CurveRequest request) {
        // 获取开始时间和结束时间
        Date startDate = request.getStartTime();
        Date endDate = request.getEndTime();
        // 创建 Calendar 对象并设置开始时间
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);

// 创建 Calendar 对象并设置结束时间
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

// 开始时间加上八小时
        startCal.add(Calendar.HOUR, 8);

// 结束时间加上八小时
        endCal.add(Calendar.HOUR, 8);

// 获取新的开始时间和结束时间
        Date newStartTime = startCal.getTime();
        Date newEndTime = endCal.getTime();
        Set<String> requiredKeys = new HashSet<>(request.getDataIds());

        // 获取请求的设备ID
        String equipmentID = request.getEquipmentID();

        // 使用Calendar来获取年份
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate); // 设置calendar的时间为startDate
        int year = calendar.get(Calendar.YEAR); // 获取年份
        String dbName = "WNMS_CSNew" + year;

        // 获取数据库引用
        MongoDatabase db = mongoClient.getDatabase(dbName);

        // 获取集合引用
        MongoCollection<Document> collection = db.getCollection(equipmentID);

        // 构建查询条件
        Bson filter = Filters.and(
                Filters.gte("UpdateTime", new Date(newStartTime.getTime())),
                Filters.lt("UpdateTime", new Date(newEndTime.getTime()))
        );

        FindIterable<Document> iterable = collection.find(filter).sort(new Document("UpdateTime", 1));
        List<Document> documents = new ArrayList<>();
        iterable.into(documents);
        List<AnalogVo> analogVoList = new ArrayList<>();

        for (Document document : documents) {
            AnalogVo analogVo = new AnalogVo();

            // 假设UpdateTime在Document中是以Date对象存储的
            Date updateTime = document.getDate("UpdateTime");
            // 将 updateTime 转换为毫秒数
            long updateTimeInMillis = updateTime.getTime();
            // 减去八小时的毫秒数
            long newTimeInMillis = updateTimeInMillis - (8 * 60 * 60 * 1000);
            // 创建新的 Date 对象
            Date newTime = new Date(newTimeInMillis);
            analogVo.setUpdateTime(newTime);

            // 假设AnalogValues在Document中是以Map<Integer, Double>对象存储的，键是整数类型
            Map<String, Double> analogValues = document.get("AnalogValues", new HashMap<>());

            // 过滤Map以仅包含所需的键
            Map<String, Double> typedAnalogValues = analogValues.entrySet().stream()
                    .filter(entry -> requiredKeys.contains(entry.getKey()))
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            analogVo.setAnalogValues(typedAnalogValues);

            // 添加转换后的AnalogVo到列表中
            analogVoList.add(analogVo);
        }

        return analogVoList;
    }
//    @Override
//    public List<CollVo> getReport2(ReportRequest request) {
//        //        mongoTemplate的聚合查询
//        List<AggregationOperation> operations = new ArrayList<>();
////        筛选指定时间的数据
//        operations.add(Aggregation.match(Criteria.where("UpdateTime")
//                .gte(request.getStartTime())
//                .lte(request.getEndTime())));
//
//        operations.add(Aggregation.sort(Direction.ASC, "UpdateTime"));
//        // 添加分页操作
//        operations.add(new SkipOperation((long) (request.getPageNum() - 1) * request.getPageSize()));
//        operations.add(new LimitOperation(request.getPageSize()));
//        Aggregation aggregation = Aggregation.newAggregation(operations);
//        AggregationResults<CollVo> aggregate
//                = mongoTemplate.aggregate(aggregation, "1711501542211", CollVo.class);
//        return aggregate.getMappedResults();
//    }
//
//    @Override
//    public List<CollVo> getReport(ReportRequest request) {
//
//        //        mongoTemplate的聚合查询
//        List<AggregationOperation> operations = new ArrayList<>();
//
//        // 构建MatchOperation
//        operations.add(Aggregation.match(
//                Criteria.where("UpdateTime").gte(request.getStartTime()).lt(request.getEndTime())
//        ));
//        // 构建ProjectOperation来计算时间差并准备分组
//        operations.add(Aggregation.project()
//                .andExpression("toLong(divide(toLong(UpdateTime), 600000))").as("timestamp")
//                .andInclude("UpdateTime", "AnalogValues"));
//
//        // 构建GroupOperation按每十分钟分组
//        operations.add(Aggregation.group("timestamp")
//                .last("timestamp").as("timestamp")
//                .last("$$ROOT").as("firstDoc"));
//        // 构建ProjectOperation来格式化日期和排除_id
//        operations.add(Aggregation.project()
//                .andExclude("_id")
//                .andExpression("toDate(multiply(timestamp, 600000))").as("UpdateTime")
//                .andInclude("firstDoc.AnalogValues"));
//
//        operations.add(Aggregation.sort(Direction.ASC, "UpdateTime"));
//
//        // 构建SkipOperation和LimitOperation以实现分页
//        operations.add(new SkipOperation((long) (request.getPageNum() - 1) * request.getPageSize()));
//        operations.add(new LimitOperation(request.getPageSize()));
//
//        // 构建聚合查询
//        Aggregation aggregation = Aggregation.newAggregation(operations);
//        // 执行聚合查询
//        AggregationResults<Document> aggregateResults = mongoTemplate.aggregate(
//                aggregation,
//                "1483684758731", // 替换为实际的集合名称
//                Document.class
//        );
//
//        // 对第二个集合执行聚合查询
//        AggregationResults<Document> aggregateResults2 = mongoTemplate.aggregate(
//                aggregation,
//                "1625537860816",
//                Document.class
//        );
//        List<Document> documents = new ArrayList<>();
//        documents.addAll(aggregateResults.getMappedResults());
//        documents.addAll(aggregateResults2.getMappedResults());
//
//        System.out.println(documents);
//
//        // 根据时间戳去重
//        Map<Object, List<Document>> groupedByTime = documents.stream()
//                .collect(Collectors.groupingBy(
//                        document -> document.get("UpdateTime"),
//                        Collectors.mapping(
//                                document -> document, // 从文档中提取整个Document对象
//                                Collectors.toList()   // 将具有相同时间戳的Document对象收集到列表中
//                        )
//                ));
//
//        // 构建最终的CollVo列表
//        List<CollVo> collVoList = new ArrayList<>();
//        for (Entry<Object, List<Document>> entry : groupedByTime.entrySet()) {
//            CollVo collVo = new CollVo();
//            collVo.setUpdateTime((Date) entry.getKey()); // 设置时间戳
//            List<Document> documentsWithSameTime = entry.getValue();
//            // 合并AnalogValues，这里需要自定义合并逻辑
//            Map<String, Double> allAnalogValues = new HashMap<>();
//            for (Document document : documentsWithSameTime) {
//                Document analogValuesDocument = (Document) document.get("AnalogValues");
//                for (String key : analogValuesDocument.keySet()) {
//                    // 合并AnalogValues的值，这里可以根据实际情况选择求和、取平均或其他逻辑
//                    allAnalogValues.merge(key, analogValuesDocument.get(key, Double.class), Double::sum);
//                }
//            }
//            collVo.setAnalogValues(allAnalogValues);
//            // 可能还需要设置其他字段...
//            collVoList.add(collVo);
//        }
//        collVoList.sort(Comparator.comparing(CollVo::getUpdateTime));
//        // 返回CollVo对象的列表
//        return collVoList;
//    }

}




